// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: declaration of .
//   $Id$



// BinaryBehavior.h : Declaration of the CBinaryBehavior

#ifndef __BINARYBEHAVIOR_H_
#define __BINARYBEHAVIOR_H_

#include "resource.h"       // main symbols
#include "xforms.h"
/////////////////////////////////////////////////////////////////////////////
// CBinaryBehavior
#include <DOM2Events.h>

//<summary>
//	This is the function registered  by COM_INTERFACE_ENTRY_FUNC in the COM Map.
//
//	When other QueryInterface methods have failed, the caller may be trying to access 
//	the masterElement.  CBinaryBehavior_MemberQueryInterface calls QueryInterface on that
//	and returns whatever happens then.
//</summary>
//<remarks>
//	The purpose of this is to behave like AGGREGATION, but there are two hurdles to doning real aggregation.
//	1: We are not allowed to store the masterElement;
//	2: In Aggregation, the aggregator class must own (and create for bidirectional QI)
//			 the aggregatee.  CBinaryBehavior does not have the chance do this.
//</remarks>

HRESULT WINAPI CBinaryBehavior_MasterQueryInterface(void* pv, REFIID riid, LPVOID* ppv, DWORD dw);
typedef IDispatchImpl<IXFormsElementState, &IID_IXFormsElementState, &LIBID_XFORMSLib,1,7> IXFormsElementStateDispatch;
typedef IDispatchImpl<IEventTarget, &IID_IEventTarget, &LIBID_DOM2EventsLib, 2,0> IEventTargetDispatch;
typedef IDispatchImpl<IBinaryBehavior, &IID_IBinaryBehavior, &LIBID_XFORMSLib> IBinaryBehaviorDispatch;
#include <Common/COM/msw/MultiIDispatch.h>


class ATL_NO_VTABLE CBinaryBehavior : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CBinaryBehavior, &CLSID_BinaryBehavior>,
	public IObjectWithSiteImpl<CBinaryBehavior>,
	//public IDispatchImpl<IBinaryBehavior, &IID_IBinaryBehavior, &LIBID_XFORMSLib>,

	// Interfaces added to implement a binary element behavior.

	public IElementBehavior,
	public IEventTargetDispatch,
	public IBinaryBehaviorDispatch,
	public IXFormsElementStateDispatch,
	public CMultiIDispatch<CBinaryBehavior>
{
	friend HRESULT WINAPI CBinaryBehavior_MasterQueryInterface(void* , REFIID , LPVOID* , DWORD );

	// Members
public:
	CBinaryBehavior();
	virtual ~CBinaryBehavior();
	virtual HRESULT DocumentReady();
	virtual HRESULT ElementReady();

	// IElementBehavior
	STDMETHOD(Init)(IElementBehaviorSite* pBehaviorSite);
	STDMETHOD(Notify)(LONG lEvent, VARIANT* pVar);
	STDMETHOD(Detach)();

	// Perform any initialisation specific to this particular behaviour. 
	//This is called by init, as the overrideable portion.
	virtual HRESULT InitBehaviour();

	static HRESULT GetNamedBehavior (BSTR sName,  IDispatch * pDispNode, IElementBehavior ** ppBehavior);


	DECLARE_REGISTRY_RESOURCEID(IDR_BINARYBEHAVIOR)

	DECLARE_PROTECT_FINAL_CONSTRUCT()
#pragma warning(disable:4244)
	BEGIN_MULTI_DISPATCH_MAP(CBinaryBehavior)
		MULTI_DISPATCH_ENTRY(IEventTargetDispatch)
		MULTI_DISPATCH_ENTRY(IXFormsElementStateDispatch)
		MULTI_DISPATCH_ENTRY(IBinaryBehaviorDispatch)
	END_MULTI_DISPATCH_MAP()
#pragma warning(default:4244)
	
	DECLARE_MULTI_DISPATCH(CBinaryBehavior)

	BEGIN_COM_MAP(CBinaryBehavior)
		COM_INTERFACE_ENTRY(IEventTarget)
		COM_INTERFACE_ENTRY(IXFormsElementState)
		COM_INTERFACE_ENTRY2(IDispatch, IBinaryBehavior)
		COM_INTERFACE_ENTRY(IObjectWithSite)
		COM_INTERFACE_ENTRY(IElementBehavior)
		COM_INTERFACE_ENTRY_FUNC(IID_IHTMLElement,0,CBinaryBehavior_MasterQueryInterface)
		COM_INTERFACE_ENTRY_FUNC(IID_IHTMLElement2,0,CBinaryBehavior_MasterQueryInterface)
		COM_INTERFACE_ENTRY_FUNC(IID_IHTMLElement3,0,CBinaryBehavior_MasterQueryInterface)
		COM_INTERFACE_ENTRY_FUNC(IID_IHTMLElement4,0,CBinaryBehavior_MasterQueryInterface)
		COM_INTERFACE_ENTRY_FUNC(IID_IHTMLDOMNode,0,CBinaryBehavior_MasterQueryInterface)
		COM_INTERFACE_ENTRY_FUNC(IID_IHTMLDOMNode2,0,CBinaryBehavior_MasterQueryInterface)
	END_COM_MAP()


	STDMETHOD(GetProperty)(BSTR /*sProperty*/, BSTR * /*sValue*/)
	{
		return E_NOTIMPL;
	};
	STDMETHOD(SetProperty)(BSTR /*sProperty*/, BSTR /* sValue*/)
	{
		return E_NOTIMPL;
	};

	// IEventTarget Methods
	STDMETHOD(addEventListener)(BSTR type, IEventListener * listener, BOOL useCapture);
	STDMETHOD(removeEventListener)(BSTR type, IEventListener * listener, BOOL useCapture);
	STDMETHOD(dispatchEvent)(IDOMEvent * evt,BOOL * pbCancelled);

protected:
	static HRESULT getCurrentStyleAsText(IHTMLElement2 * pSource, BSTR * pbsRetVal);
	static HRESULT copyStyle( IHTMLElement2 * pSource, IHTMLElement *pTarget );
	static HRESULT copyStyle( IHTMLElement2 * pSource, IHTMLElementDefaults *pTarget );
	// It is advisable not to store the masterelement,
	//	as it can prevent detach events from occuring.  
	//	When access is needed, use this method.
	inline HRESULT GetMasterElement(IHTMLElement ** ppMasterElement) const;
	// fires custom events out to the host document.
	inline HRESULT FireEvent(long lEventCookie, IHTMLEventObj * pEventObj);
	// Registers a custom event to be called by FireEvent
	inline HRESULT RegisterEvent(BSTR const sName, long * plCookie);
	// sets the various properties related to viewlink on a behaviour
	HRESULT SetViewlinkProperties(IHTMLDocument * pVLDoc , VARIANT_BOOL bInheritStyle, VARIANT_BOOL bTabstop, VARIANT_BOOL bMasterTab);
	// fetches the document used as the viewlink (if any)
	inline HRESULT GetViewlinkDoc(IHTMLDocument ** pDoc);

	// <summary>registers this as a named behavior</summary>
	inline HRESULT RegisterName(BSTR bsName);
	inline HRESULT CreateEventObject(IHTMLEventObj ** ppEvObj);

private:
	CComQIPtr<IElementBehaviorSiteOM> m_pSiteOM;
	CComPtr<IElementBehaviorSite> m_pSite;
	CComPtr<IHTMLElementDefaults> m_pDefaults;

};

inline HRESULT CBinaryBehavior::RegisterName(BSTR bsName)
{
	HRESULT hr = E_FAIL;
	if(m_pSiteOM)
		hr = m_pSiteOM->RegisterName(bsName);
	return hr;
}

// It is advisable not to store the masterelement, as it can prevent detach events from occuring.  When access is needed, use this method
inline HRESULT CBinaryBehavior::GetMasterElement(IHTMLElement ** ppMasterElement) const
{
	HRESULT hr = S_FALSE;
	if(m_pSite)
		hr = m_pSite->GetElement(ppMasterElement);
	else
		*ppMasterElement = 0;
	return hr;
}

// fires custom events out to the host document.
inline HRESULT CBinaryBehavior::FireEvent(long lEventCookie, IHTMLEventObj * pEventObj)
{
	return (m_pSiteOM ? m_pSiteOM->FireEvent(lEventCookie,pEventObj) : E_FAIL);
}

// Registers a custom event to be called by FireEvent
inline HRESULT CBinaryBehavior::RegisterEvent(BSTR const sName, long * plCookie)
{
	return (m_pSiteOM ? m_pSiteOM->RegisterEvent(sName,0,plCookie) : E_FAIL);
}

// fetches the document used as the viewlink (if any)
inline HRESULT CBinaryBehavior::GetViewlinkDoc(IHTMLDocument ** ppDoc)
{
	HRESULT hr = S_FALSE;
	if(m_pDefaults)
	{
		hr = m_pDefaults->get_viewLink(ppDoc);
	}
	else
	{
		*ppDoc = 0;
	}

	return hr;
}

inline HRESULT CBinaryBehavior::CreateEventObject(IHTMLEventObj ** ppEvObj)
{
	return (m_pSiteOM ? m_pSiteOM->CreateEventObject(ppEvObj): E_FAIL);
}
OBJECT_ENTRY_AUTO(__uuidof(BinaryBehavior), CBinaryBehavior)
#endif //__BINARYBEHAVIOR_H_
